#include "lib/decoders/wav/pvmvoicewav.h"

#include "lib/memory/pvmmemory.h"

PVMVoiceWAV* PVMVoiceWAV::Create(PVMDataSourceWAV* dataSource, int /*samplesPerSecond*/, int /*bitsPerSample*/, int /*chanelsNum*/)
{
	PVMVoiceWAV* voice = new PVMVoiceWAV();

	if(!voice)
		return NULL;

	if(!voice->Init(dataSource))
	{
		delete( voice);
		voice = NULL;
	}

	return voice;
}

PVMVoiceWAV::PVMVoiceWAV()
{
	dataSource = NULL;
	paused = false;
	isAlive = false;
	loopCount = 0;
	loopStart = loopEnd = -1;
}

PVMVoiceWAV::~PVMVoiceWAV()
{
	if(dataSource)
		dataSource->Release();
	dataSource = NULL;
	paused = false;
	loopCount = 0;
	isAlive = false;
}

bool PVMVoiceWAV::Init(PVMDataSourceWAV* source)
{
	dataSource = source;
	dataSource->AddRef();
	isAlive = true;
	return true;
}

void PVMVoiceWAV::GetFormat(pvm_uint32 &samplesPerSecond, pvm_uint32 &bitsperSample, pvm_uint32 &chanels)
{
	samplesPerSecond = bitsperSample = chanels = 0;
	if(dataSource!=NULL)
	{
		samplesPerSecond = dataSource->formatHeader.sampleRate;
		chanels = dataSource->formatHeader.numChannels;
		bitsperSample = dataSource->formatHeader.bitsPerSample;
	}
}

pvm_uint32 PVMVoiceWAV::GetSamplesPerSecond()
{
	if(dataSource==NULL)
		return 0;

	return dataSource->formatHeader.sampleRate;
}

pvm_uint32 PVMVoiceWAV::GetBitsPerSample()
{
	if(dataSource==NULL)
		return 0;

	return dataSource->formatHeader.bitsPerSample;
}

pvm_uint32 PVMVoiceWAV::GetChanelsNum()
{
	if(dataSource==NULL)
		return 0;

	return dataSource->formatHeader.numChannels;
}

void PVMVoiceWAV::SetLoopCount(pvm_int32 loopCount)
{
	this->loopCount = loopCount;
}

pvm_int32 PVMVoiceWAV::GetLoopCount()
{
	return loopCount;
}

void PVMVoiceWAV::SetPause(pvm_bool pause)
{
	this->paused = pause;
}

pvm_bool PVMVoiceWAV::SetLoopInSamples(pvm_int64 loopFrom, pvm_int64 loopTo)
{
	pvm_int64 dataSizeInSamples = dataSource->dataSize/dataSource->sampleSizeInBytes;
	if(loopFrom!=-1 && loopFrom>=dataSizeInSamples ||
		loopTo!=-1 && loopTo>=dataSizeInSamples)
	{
		return false;
	}

	this->loopStart = loopFrom;
	this->loopEnd = loopTo;

	return true;
}

pvm_bool PVMVoiceWAV::GetLoopInSamples(pvm_int64 &loopFrom, pvm_int64 &loopTo)
{
	loopFrom = this->loopStart;
	loopTo = this->loopEnd;
	return true;
}

pvm_bool PVMVoiceWAV::GetLoopInMS(pvm_int32 &loopFrom, pvm_int32 &loopTo)
{
	int devider = GetChanelsNum()*GetSamplesPerSecond();
	loopFrom = (pvm_int32)(this->loopStart*1000/devider);
	loopTo = (pvm_int32)(this->loopEnd*1000/devider);
	return true;
}

pvm_bool PVMVoiceWAV::GetPause()
{
	return paused;
}

pvm_uint32 PVMVoiceWAV::FillBuffer(void *buffer, pvm_uint32 numSamples)
{
	if(loopCount==0 || isAlive==false)
		return 0;

	pvm_uint32 samplesFilled = 0;
	pvm_uint32 sampleSize = dataSource->formatHeader.bitsPerSample>>3;

	while(samplesFilled<numSamples)
	{
		pvm_int nSamplesFill = numSamples - samplesFilled;
		pvm_bool forceLoopFlag = false;

		if(loopStart >=0 && loopEnd>=0 && loopCount!=1)
		{
			if(dataSource->offsetInSamples + nSamplesFill >loopStart)
			{
				nSamplesFill = (pvm_int)(loopStart - dataSource->offsetInSamples);
			}
		}

		if(nSamplesFill>0)
			samplesFilled += dataSource->FillBuffer(((char*)buffer) + samplesFilled*sampleSize, nSamplesFill);

		if(dataSource->offsetInSamples == loopStart && loopCount!=1)
		{
				forceLoopFlag = true;
		}

		if((samplesFilled<numSamples&&dataSource->IsDataEnd()) || forceLoopFlag)
		{
			if(loopCount>0)
				loopCount--;
			if(loopCount!=0)
			{
				if(loopEnd>=0)
				{
					if(dataSource->SeekAtSamplePos(loopEnd)==false)
					{
						isAlive = false;
						break;
					}
				}
				else if(dataSource->SeekAtStart()==false)
				{
					isAlive = false;
					break;
				}
			}
			else
			{
				isAlive = false;
				break;
			}
		}
	}

	return samplesFilled;
}

pvm_bool PVMVoiceWAV::IsAlive()
{
	return isAlive;
}

void PVMVoiceWAV::DoDestroy()
{
	delete( this);
}

void PVMVoiceWAV::OnIdle()
{

}

pvm_bool PVMVoiceWAV::SetPositionMS(pvm_int32 position)
{
	if(!dataSource)
		return false;

	return dataSource->SetPositionMS(position);
}

pvm_int32 PVMVoiceWAV::GetPositionMS()
{
	if(!dataSource)
		return -1;

	return dataSource->GetPositionMS();
}

pvm_bool PVMVoiceWAV::GetOption(const pvm_char* /*optionName*/, void* /*optionVal*/, pvm_uint32* /*optionSize*/)
{
	return false;
}

pvm_bool PVMVoiceWAV::SetOption(const pvm_char* /*optionName*/, void* /*optionVal*/, pvm_uint32 /*optionSize*/)
{
	return false;
}
